package com.homework.bean.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 切⾯
 * 切⼊点和通知的抽象 （与⾯向对象中的 类 相似）
 * 定义 切⼊点和通知 （切⼊点定义了要拦截哪些类的哪些⽅法，通知则定义了拦截过⽅法后要				做什么）
 */
@Component // 将对象交给IOC容器去实例化
@Aspect // 声明当前类是⼀个切⾯
public class LogCut {
    /**
     * 切⼊点：
     * 匹配规则。规定什么⽅法被拦截、需要处理什么⽅法
     * 定义切⼊点
     * @Pointcut("匹配规则")
     *
     * Aop 切⼊点表达式简介
     * 1. 执⾏任意公共⽅法：
     * execution(public *(..))
     * 2. 执⾏任意的set⽅法
     * execution(* set*(..))
     * 3. 执⾏com.xxxx.service包下任意类的任意⽅法
     * execution(* com.xxxx.service.*.*(..))
     * 4. 执⾏com.xxxx.service 包 以及⼦包下任意类的任意⽅法
     * execution(* com.xxxx.service..*.*(..))
     *
     * 注：表达式中的第⼀个* 代表的是⽅法的修饰范围
     * 可选值：private、protected、public （* 表示所有范围）
     */
    @Pointcut("execution (* com.xxxx.service..*.*(..) )")
    public void cut(){}
    /**
     * 声明前置通知 并将通知应⽤到定义的切⼊点上
     * ⽬标类⽅法执⾏前 执⾏该通知
     *
     */
    @Before(value = "cut()")
    public void before() {
        System.out.println("前置通知.....");
    }
    /**
     * 声明返回通知 并将通知应⽤到定义的切⼊点上
     * ⽬标类⽅法（⽆异常）执⾏后 执⾏该通知
     *
     */
    @AfterReturning(value = "cut()")
    public void afterReturn() {
        System.out.println("返回通知.....");
    }
    /**
     * 声明最终通知 并将通知应⽤到定义的切⼊点上
     * ⽬标类⽅法（⽆异常或有异常）执⾏后 执⾏该通知
     *
     */
    @After(value = "cut()")
    public void after() {
        System.out.println("最终通知.....");
    }
    /**
     * 声明异常通知 并将通知应⽤到定义的切⼊点上
     * ⽬标类⽅法出现异常时 执⾏该通知
     */
    @AfterThrowing(value="cut()",throwing = "e")
    public void afterThrow(Exception e) {
        System.out.println("异常通知....." + " 异常原因：" + e.getCause());
    }
    /**
     * 声明环绕通知 并将通知应⽤到切⼊点上
     * ⽅法执⾏前后 通过环绕通知定义相应处理
     * 需要通过显式调⽤对应的⽅法，否则⽆法访问指定⽅法 (pjp.proceed();)
     * @param pjp
     * @return
     */
    @Around(value = "cut()")
    public Object around(ProceedingJoinPoint pjp) {
        System.out.println("前置通知...");
        Object object = null;
        try {
            object = pjp.proceed();
            System.out.println(pjp.getTarget() + "======" +
                    pjp.getSignature());
            // System.out.println("返回通知...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知...");
        }
        System.out.println("最终通知...");
        return object;
    }
}

